unit untEditors;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Contnrs;

type

{ TEditorList }

TEditor = class
  private
    FFilename: String;
    FData: TStringList;
    FChanged: Boolean;
    function GetCaption: String;
    function GetTemporaryFilename: String;
  public
    constructor Create;
    destructor Destroy; override;
    procedure LoadFromFile(const AFilename: String);
    function SaveToFile(const AFilename: String = ''): Boolean;
    property Caption: String read GetCaption;
    property Filename: String read FFilename;
    property TemporaryFilename: String read GetTemporaryFilename;
    property Data: TStringList read FData;
    property Changed: Boolean read FChanged write FChanged;
end;

TEditorList = class(TObjectList)
  private
    FItemIndex: Integer;
    function GetCurrentFilename: String;
    function GetFileChanged: Boolean;
    procedure SetFileChanged(const AChanged: Boolean);
  public
    constructor Create;
    destructor Destroy; override;
    function CreateFile: Integer;
    function OpenFile(const AFilename: String): Integer;
    function SaveFile(const AFilename: String = ''): Boolean;
    procedure SaveBuffer(const ALines: TStrings; const AItemIndex: Integer = -1);
    procedure CloseFile;
    procedure ListFiles(var AStrings: TStrings);
    procedure SwitchToFile(const AIndex: Integer; const ALines: TStrings);
    property ItemIndex: Integer read FItemIndex;
    property Filename: String read GetCurrentFilename;
    property FileChanged: Boolean read GetFileChanged write SetFileChanged;
end;

implementation

{ TEditorList }

function TEditorList.GetCurrentFilename: String;
begin
  if FItemIndex = -1 then
    Result := ''
  else
    Result := TEditor(Items[FItemIndex]).Filename;
end;

function TEditorList.GetFileChanged: Boolean;
begin
  Result := False;
  if FItemIndex = -1 then Exit;
  Result := TEditor(Items[FItemIndex]).Changed;
end;

procedure TEditorList.SetFileChanged(const AChanged: Boolean);
begin
  if FItemIndex = -1 then Exit;
  TEditor(Items[FItemIndex]).Changed := AChanged;
end;

constructor TEditorList.Create;
begin
  inherited Create;
  FItemIndex := -1;
end;

destructor TEditorList.Destroy;
begin
  inherited Destroy;
end;

function TEditorList.CreateFile: Integer;
begin
  Result := Add(TEditor.Create);
end;

function TEditorList.OpenFile(const AFilename: String): Integer;
var i : Integer;
begin
  // First check if the file is already open somewhere
  for i := 0 to Count - 1 do
    if TEditor(Items[i]).Filename = AFilename then
    begin
      Result := i;
      Exit;
    end;
  // Otherwise, create a new editor and load the requested file inside
  i := CreateFile;
  TEditor(Items[i]).LoadFromFile(AFilename);
  Result := i;
end;

function TEditorList.SaveFile(const AFilename: String = ''): Boolean;
begin
  Result := False;
  if FItemIndex = -1 then Exit;
  Result := TEditor(Items[ItemIndex]).SaveToFile(AFilename);
end;

procedure TEditorList.SaveBuffer(const ALines: TStrings;
  const AItemIndex: Integer);
var i : Integer;
    Editor: TEditor;
begin
  if AItemIndex = -1 then i := FItemIndex else i := AItemIndex;
  if i = -1 then Exit;
  Editor := TEditor(Items[i]);
  Editor.Data.Assign(ALines);
  if (Editor.Filename <> '') and Editor.Changed then
    Editor.Data.SaveToFile(Editor.TemporaryFilename);
end;

procedure TEditorList.CloseFile;
begin
  if FItemIndex > -1 then
    Delete(FItemIndex);
  FItemIndex := -1;
end;

procedure TEditorList.ListFiles(var AStrings: TStrings);
var i : Integer;
begin
  AStrings.Clear;
  for i := 0 to Count - 1 do
    AStrings.Add(TEditor(Items[i]).Caption);
end;

procedure TEditorList.SwitchToFile(const AIndex: Integer; const ALines: TStrings);
begin
  SaveBuffer(ALines, FItemIndex);
  if (AIndex >= 0) and (AIndex < Count) then
  begin
    FItemIndex := AIndex;
    ALines.Assign(TEditor(Items[FItemIndex]).Data);
  end;
end;

{ TEditor }

function TEditor.GetCaption: String;
begin
  if FFilename = '' then
  begin
    Result := '(untitled)';
  end
  else
  begin
    Result := ExtractFileName(FFilename);
  end;
  if FChanged then
    Result := Result + '*';
end;

function TEditor.GetTemporaryFilename: String;
begin
  if FFilename = '' then
    Result := ''
  else
    Result := ExtractFilePath(FFilename) + '~' + ExtractFileName(FFilename);
end;

constructor TEditor.Create;
begin
  FFilename := '';
  FData := TStringList.Create;
end;

destructor TEditor.Destroy;
begin
  FData.Free;
  inherited Destroy;
end;

procedure TEditor.LoadFromFile(const AFilename: String);
begin
  FFilename := AFilename;
  FData.LoadFromFile(AFilename);
end;

function TEditor.SaveToFile(const AFilename: String): Boolean;
begin
  Result := False;
  if (AFilename = '') and (FFilename = '') then Exit;
  if (AFilename <> '') then FFilename := AFilename;
  FData.SaveToFile(FFilename);
  FChanged := False;
  DeleteFile(TemporaryFilename);
  Result := True;
end;

end.

